use std::{fs::{File, OpenOptions}, io::{BufRead, BufReader, Read, Write}};

use super::Instruction;

pub fn parse_instruction_file<S: AsRef<str>>(instruction_file_path: S) -> Vec<(Instruction, i32)> {
    let mut code_list = Vec::default();
    let f = File::open(instruction_file_path.as_ref());
    if f.is_err() {
        panic!("打开文件失败");
    }
    let mut buf = String::default();
    let mut reader = BufReader::new(f.unwrap());
    for line in reader.lines() {
        let line = line.unwrap();
        let line_char = line.chars().collect::<Vec<_>>();
        let line_char_slice = line_char.as_slice();
        match line_char_slice {
            ['L', 'D', 'C', ' ', ..] => code_list.push((Instruction::LDC, line[4..].parse().unwrap())),
            ['L', 'D'] => code_list.push((Instruction::LD, 0)),
            ['A', 'L', 'D'] => code_list.push((Instruction::ALD, 0)),
            ['S', 'T'] => code_list.push((Instruction::ST, 0)),
            ['A', 'S', 'T'] => code_list.push((Instruction::AST, 0)),
            ['P', 'U', 'S', 'H'] => code_list.push((Instruction::PUSH, 0)),
            ['P', 'O', 'P'] => code_list.push((Instruction::POP, 0)),
            ['J', 'M', 'P', ' ', ..] => code_list.push((Instruction::JMP, line[4..].parse().unwrap())),
            ['J', 'Z', ' ', ..] => code_list.push((Instruction::JZ, line[3..].parse().unwrap())),
            ['A', 'D', 'D'] => code_list.push((Instruction::ADD, 0)),
            ['S', 'U', 'B'] => code_list.push((Instruction::SUB, 0)),
            ['M', 'U', 'L'] => code_list.push((Instruction::MUL, 0)),
            ['D', 'I', 'V'] => code_list.push((Instruction::DIV, 0)),
            ['L', 'T'] => code_list.push((Instruction::LT, 0)),
            ['L', 'E'] => code_list.push((Instruction::LE, 0)),
            ['G', 'T'] => code_list.push((Instruction::GT, 0)),
            ['G', 'E'] => code_list.push((Instruction::GE, 0)),
            ['E', 'Q'] => code_list.push((Instruction::EQ, 0)),
            ['N', 'E'] => code_list.push((Instruction::NE, 0)),
            ['I', 'N'] => code_list.push((Instruction::IN, 0)),
            ['O', 'U', 'T'] => code_list.push((Instruction::OUT, 0)),
            ['A', 'D', 'D', 'R', ' ', ..] => code_list.push((Instruction::ADDR, line[5..].parse().unwrap())),
            ['C', 'A', 'L', 'L', ' ', ..] => code_list.push((Instruction::CALL, line[5..].parse().unwrap())),
            ['R', 'E', 'T'] => code_list.push((Instruction::RET, 0)),
            _ => {}
        }
    }
    code_list
}
pub fn output_instruction<S: AsRef<str>>(instruction_file_path: S, code_list: &Vec<(Instruction, String)>) {
    let f = File::create(instruction_file_path.as_ref());
    if f.is_err() {
        panic!("创建文件失败");
    }
    let mut f = f.unwrap();
    for (code_enum, code_val_str) in code_list {
        match code_enum {
            Instruction::LDC => {f.write_fmt(format_args!("LDC {}\n", code_val_str));}
            Instruction::LD => {f.write_fmt(format_args!("LD\n"));}
            Instruction::ALD => {f.write_fmt(format_args!("ALD\n"));}
            Instruction::ST => {f.write_fmt(format_args!("ST\n"));}
            Instruction::AST => {f.write_fmt(format_args!("AST\n"));}
            Instruction::PUSH => {f.write_fmt(format_args!("PUSH\n"));}
            Instruction::POP => {f.write_fmt(format_args!("POP\n"));}
            Instruction::JMP => {f.write_fmt(format_args!("JMP {}\n", code_val_str));}
            Instruction::JZ => {f.write_fmt(format_args!("JZ {}\n", code_val_str));}
            Instruction::ADD => {f.write_fmt(format_args!("ADD\n"));}
            Instruction::SUB => {f.write_fmt(format_args!("SUB\n"));}
            Instruction::MUL => {f.write_fmt(format_args!("MUL\n"));}
            Instruction::DIV => {f.write_fmt(format_args!("DIV\n"));}
            Instruction::LT => {f.write_fmt(format_args!("LT\n"));}
            Instruction::LE => {f.write_fmt(format_args!("LE\n"));}
            Instruction::GT => {f.write_fmt(format_args!("GT\n"));}
            Instruction::GE => {f.write_fmt(format_args!("GE\n"));}
            Instruction::EQ => {f.write_fmt(format_args!("EQ\n"));}
            Instruction::NE => {f.write_fmt(format_args!("NE\n"));}
            Instruction::IN => {f.write_fmt(format_args!("IN\n"));}
            Instruction::OUT => {f.write_fmt(format_args!("OUT\n"));}
            Instruction::ADDR => {f.write_fmt(format_args!("ADDR {}\n", code_val_str));}
            Instruction::CALL => {f.write_fmt(format_args!("CALL {}\n", code_val_str));}
            Instruction::RET => {f.write_fmt(format_args!("RET\n"));}
        }
    }
    f.flush();
}